package pku.edu.cn.context.client;

import java.util.HashMap;

import org.alljoyn.bus.BusAttachment;
import org.alljoyn.bus.BusException;
import org.alljoyn.bus.BusListener;
import org.alljoyn.bus.Mutable;
import org.alljoyn.bus.ProxyBusObject;
import org.alljoyn.bus.SessionListener;
import org.alljoyn.bus.SessionOpts;
import org.alljoyn.bus.Status;

import pku.edu.cn.context.client.Context.Data;

import android.app.Activity;
import android.app.Dialog;
import android.app.ProgressDialog;
import android.content.res.Resources;
import android.os.Bundle;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Looper;
import android.os.Message;
import android.util.Log;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.ListView;
import android.widget.TableLayout;
import android.widget.TableRow;
import android.widget.TextView;
import android.widget.Toast;

/*
 * This is a sample client that will receive information about the contexts stored on
 * the phone from a contexts service.
 */
public class ContextClient extends Activity {
    static {
        System.loadLibrary("alljoyn_java");
    }

    private static final int DIALOG_CONTACT = 1;
    
    private static final int MESSAGE_DISPLAY_ALL_CONTACTS = 1;
    private static final int MESSAGE_DISPLAY_CONTACT = 2;
    private static final int MESSAGE_POST_TOAST = 3;
    private static final int MESSAGE_START_PROGRESS_DIALOG = 4;
    private static final int MESSAGE_STOP_PROGRESS_DIALOG = 5;

    private static final String TAG = "ContextsClient";
    
    private Button mGetContextsBtn;
    private ArrayAdapter<String> mContextsListAdapter;
    private ListView mContextsListView;
    private Menu menu;

    private Context mContextEntry;
    private NameId[] mContextNames;
    
    String mSingleName;
    int mSingleUserId;

    BusHandler mBusHandler;
    private ProgressDialog mDialog;
    
    private Handler mHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
            case MESSAGE_DISPLAY_ALL_CONTACTS: 
                mContextNames = (NameId[]) msg.obj;
                /*
                 * Make sure the Contexts list is clear of any old information before filling the list.
                 */
                mContextsListAdapter.clear();
                
                /*
                 * Change the name of the button from "Get Contexts List" to "Update Contexts List"
                 */
                mGetContextsBtn.setText(getString(R.string.update_contexts));
                for (int i = 0; i < mContextNames.length; i++) {
                    mContextsListAdapter.add(mContextNames[i].displayName);
                }
                break;
            case MESSAGE_DISPLAY_CONTACT:
                mContextEntry = (Context) msg.obj;
                showDialog(DIALOG_CONTACT);
                break;
            case MESSAGE_POST_TOAST:
                Toast.makeText(getApplicationContext(), (String) msg.obj, Toast.LENGTH_LONG).show();
                break;
            case MESSAGE_START_PROGRESS_DIALOG:
                mDialog = ProgressDialog.show(ContextClient.this, 
                                              "", 
                                              "Finding Contexts Service.\nPlease wait...", 
                                              true,
                                              true);
                break;
            case MESSAGE_STOP_PROGRESS_DIALOG:
                mDialog.dismiss();
                break;                
            default:
                break;
            }
        }
    };
    
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        mContextsListAdapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1);
        mContextsListView = (ListView) findViewById(R.id.context_list);
        mContextsListView.setAdapter(mContextsListAdapter);
        mContextsListView.setTextFilterEnabled(true);
        mContextsListView.setOnItemClickListener(new GetContextInformation());

        mGetContextsBtn = (Button) findViewById(R.id.get_contexts_btn);
        mGetContextsBtn.setOnClickListener(new GetContextsListener());

        mContextEntry = new Context();

        HandlerThread busThread = new HandlerThread("BusHandler");
        busThread.start();
        mBusHandler = new BusHandler(busThread.getLooper());
        mBusHandler.sendEmptyMessage(BusHandler.CONNECT);
        mHandler.sendEmptyMessage(MESSAGE_START_PROGRESS_DIALOG);
    }
    
    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        MenuInflater inflater = getMenuInflater();
        inflater.inflate(R.menu.mainmenu, menu);
        this.menu = menu;
        return true;
    }
    
    @Override
	public boolean onOptionsItemSelected(MenuItem item) {
	    switch (item.getItemId()) {
	    case R.id.quit:
	    	finish();
	        return true;
	    default:
	        return super.onOptionsItemSelected(item);
	    }
	}
    
    @Override
    protected void onDestroy() {
        super.onDestroy();
        mBusHandler.sendEmptyMessage(BusHandler.DISCONNECT);
    }

    /**
     * Implementation of the OnClickListener attached to the "Get Contexts List"
     * "Update Contexts List"  button.  When clicked this will fill the 
     * mcontextsListAdapter with an alphabetized list of all the contexts on
     * the phone.
     */
    private class GetContextsListener implements View.OnClickListener {
        public void onClick(View v) {
            mBusHandler.sendEmptyMessage(BusHandler.GET_ALL_CONTACT_NAMES);
        }
    }

    /**
     * Implementation of the OnItemClickListener for any item in the contexts
     * list.  The listener will use the the string from the list and use that
     * name to lookup an individual context based on that name.
     */
    private class GetContextInformation implements AdapterView.OnItemClickListener {
        public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
            Message msg = mBusHandler.obtainMessage(BusHandler.GET_CONTACT, mContextNames[position]);
            mBusHandler.sendMessage(msg);
        }
    }

    @Override
    protected Dialog onCreateDialog(int id) {
        Dialog dialog = null;
        try {
            switch (id) {
            case DIALOG_CONTACT: {
                dialog = new Dialog(ContextClient.this);
                break;
            }
            default: {
                dialog = null;
                break;
            }
            }
        } catch (Throwable ex ) {
            Log.e(TAG, String.format("Throwable exception found"), ex);
        }
        return dialog;
    }

    @Override
    protected void onPrepareDialog(int id, Dialog dialog) {
        switch (id) {
        /*
         * build a dialog that show the contents of the an individual context
         * This will dynamically build the dialog based on how much information 
         * is known about the context. 
         */
        case DIALOG_CONTACT: {
            /*
             * Individual dialog elements
             */

            /*
             * Reset the dialog to a known starting point
             */
            dialog.setContentView(R.layout.context);
            dialog.setTitle(getString(R.string.context_dialog_title));

            /*
             * Add the context Name to the top of the table
             */
            TextView contextName = (TextView) dialog.findViewById(R.id.context_name);
            contextName.setText(mContextEntry.type);
            TextView contextTime = (TextView) dialog.findViewById(R.id.context_time);
            contextTime.setText(mContextEntry.time);
            TextView contextData = (TextView) dialog.findViewById(R.id.context_data_name);
            contextData.setText(mContextEntry.data.name);
            TextView contextContent = (TextView) dialog.findViewById(R.id.context_data_content);
            contextContent.setText(mContextEntry.data.content);
            TextView contextDetail= (TextView) dialog.findViewById(R.id.context_data_detail);
            contextDetail.setText(mContextEntry.data.detail);
            
            
            }

            break;
        
        default:
            break;
        }
    }
    
    /**
     * Insert a phone number into the table at the indicated position
     *//*
    private void insertDataToTable(TableLayout table, Data data) {
    	int position = 1;
        TableRow tr = new TableRow(getApplicationContext());
        TextView type = new TextView(getApplicationContext());
        type.setLayoutParams(new TableRow.LayoutParams(1));
        TextView content = new TextView(getApplicationContext());
        TextView detail = new TextView(getApplicationContext());
        detail.setLayoutParams(new TableRow.LayoutParams(2));

       // for(int i=0;i<data.size();i++){
        //	if(data.containsKey("wifi")){
        		type.setText(data.name);
        		content.setText(data.content);
        		detail.setText(data.detail);
        		tr.addView(type);
                tr.addView(content);
                tr.addView(detail);
                table.addView(tr, position);
        //	}
       // }
        
    }*/
    /*
     * See the SimpleClient sample for a more complete description of the code used 
     * to connect this code to the Bus
     */
    class BusHandler extends Handler {
        private static final String SERVICE_NAME = "org.alljoyn.bus.awareness";
        private static final short CONTACT_PORT = 42;
        
        public static final int CONNECT = 1;
        public static final int DISCONNECT = 2;
        public static final int GET_CONTACT = 3;
        public static final int GET_ALL_CONTACT_NAMES = 4;
        public static final int JOIN_SESSION = 5;
        
        private BusAttachment mBus;
        private ProxyBusObject mProxyObj;
        private AwarenessInterface mAwarenessInterface;
        
        private int     mSessionId;
        private boolean mIsConnected;
        private boolean mIsStoppingDiscovery;
        
        public BusHandler(Looper looper) {
            super(looper);
            mIsConnected = false;
            mIsStoppingDiscovery = false;
        }
        
        @Override
        public void handleMessage(Message msg) {
            switch(msg.what) {
            case CONNECT: {
            	org.alljoyn.bus.alljoyn.DaemonInit.PrepareDaemon(getApplicationContext());
                mBus = new BusAttachment(getPackageName(), BusAttachment.RemoteMessage.Receive);
                
                mBus.registerBusListener(new BusListener() {
                    @Override
                    public void foundAdvertisedName(String name, short transport, String namePrefix) {
                    	logInfo(String.format("MyBusListener.foundAdvertisedName(%s, 0x%04x, %s)", name, transport, namePrefix));
                    	/*
                         * This client will only join the first service that it sees advertising
                         * the indicated well-known name.  If the program is already a member of 
                         * a session (i.e. connected to a service) we will not attempt to join 
                         * another session.
                         * It is possible to join multiple session however joining multiple 
                         * sessions is not shown in this sample. 
                         */
                    	if (! mIsConnected){
                    	    Message msg = obtainMessage(JOIN_SESSION, name);
                    	    sendMessage(msg);
                    	}
                    }
                });

                Status status = mBus.connect();
                logStatus("BusAttachment.connect()", status);
                
                status = mBus.findAdvertisedName(SERVICE_NAME);
                logStatus(String.format("BusAttachement.findAdvertisedName(%s)", SERVICE_NAME), status);
                break;
            }
            case JOIN_SESSION: {
                if (mIsStoppingDiscovery) {
                    break;
                }

                short contextPort = CONTACT_PORT;
                SessionOpts sessionOpts = new SessionOpts();
                Mutable.IntegerValue sessionId = new Mutable.IntegerValue();

                Status status = mBus.joinSession((String) msg.obj, contextPort, sessionId, sessionOpts, new SessionListener(){
                    @Override
                    public void sessionLost(int sessionId) {
                        mIsConnected = false;
                        logInfo(String.format("MyBusListener.sessionLost(%d)", sessionId));
                        mHandler.sendEmptyMessage(MESSAGE_START_PROGRESS_DIALOG);
                    }
                });
                logStatus("BusAttachment.joinSession()", status);

                if (status == Status.OK) {
                	mProxyObj = mBus.getProxyBusObject(SERVICE_NAME, "/awareness", sessionId.value,
                				                       new Class[] { AwarenessInterface.class });
                	mAwarenessInterface = mProxyObj.getInterface(AwarenessInterface.class);
                	mSessionId = sessionId.value;
                	mIsConnected = true;
                	mHandler.sendEmptyMessage(MESSAGE_STOP_PROGRESS_DIALOG);
                }
                break;
            }

            case DISCONNECT: {
                mIsStoppingDiscovery = true;
                if (mIsConnected) {
                    Status status = mBus.leaveSession(mSessionId);
                    logStatus("BusAttachment.leaveSession()", status);
                }
                mBus.disconnect();
                getLooper().quit();
                break;


            }
            // Call awarenessInterface.getContext method and send the result to the UI handler.
            case GET_CONTACT: {
                if (mAwarenessInterface == null) {
                	break;
                }
            	try {
                    NameId nameId = (NameId)msg.obj;
                    Context reply = mAwarenessInterface.getContext(nameId.displayName, nameId.userId);
                    Message replyMsg = mHandler.obtainMessage(MESSAGE_DISPLAY_CONTACT, reply);
                    mHandler.sendMessage(replyMsg);
                } catch (BusException ex) {
                    logException("AwarenessInterface.getContext()", ex);
                }
                break;
            }
            // Call AwarenessInterface.getAllContextNames and send the result to the UI handler
            case GET_ALL_CONTACT_NAMES: {
                try {
                	Log.i(TAG, String.format("here"));
                    NameId[] reply = mAwarenessInterface.getAllContextNames();
                    Message replyMsg = mHandler.obtainMessage(MESSAGE_DISPLAY_ALL_CONTACTS, (Object) reply);
                    mHandler.sendMessage(replyMsg);
                } catch (BusException ex) {
                    logException("AwarenessInterface.getAllContextNames()", ex);
                }
                break;
            }
            default:
                break;
            }
        }
    }
        
    private void logStatus(String msg, Status status) {
        String log = String.format("%s: %s", msg, status);
        if (status == Status.OK) {
            Log.i(TAG, log);
        } else {
            Message toastMsg = mHandler.obtainMessage(MESSAGE_POST_TOAST, log);
            mHandler.sendMessage(toastMsg);
            Log.e(TAG, log);
        }
    }

    private void logException(String msg, BusException ex) {
        String log = String.format("%s: %s", msg, ex);
        Message toastMsg = mHandler.obtainMessage(MESSAGE_POST_TOAST, log);
        mHandler.sendMessage(toastMsg);
        Log.e(TAG, log, ex);
    }
    
    private void logInfo(String msg) {
        Log.i(TAG, msg);
    }
}